﻿new function(jQun, Class, Interface, Enum, HTMLElementList, Event, HTML, defineProperties){

this.SlideTypes = (function(){
	return new Enum(
		[ "PC", "Mobile" ]
	);
}());

this.SlideDirs = (function(){
	return new Enum(
		["Horizontal", "Vertical"]
	);
}());

this.SlideTabSwitchStatus = (function(){
	return new Enum(
		["Previous", "Next", "Init"]
	);
}());

this.SlideTab = (function(SlideTabSwitchStatus, switchtabEvent, unswitchtabEvent, ceil){
	function SlideTab(selector, _isLoop){
		this.assign({
				boundParentList : this.parent(),
				isLoop : _isLoop,
				max : this.length - 1
			})
			.toSwitch(
				0,
				SlideTabSwitchStatus.Init
			)
			.classList
			.add(
				"slideTab"
			);
	};
	SlideTab = new Class(SlideTab, "jQun.SlideTab", HTMLElementList.prototype);

	SlideTab.props({
		boundParentList : null,
		breakLoop : function(){
			this.isLoop = false;

			return this;
		},
		index : 0,
		isLoop : true,
		max : 0,
		next : function(){
			this.toSwitch(this.index + 1, SlideTabSwitchStatus.Next);
			return this;
		},
		openLoop : function(){
			this.isLoop = true;

			return this;
		},
		previous : function(){
			this.toSwitch(
					this.index - 1,
					SlideTabSwitchStatus.Previous
				);

			return this;
		},
		reshow : function(lastIndex, switchStatus){
			var children = this.boundParentList.children;

			this.removeData(
					"switchstatus"
				)
				.hide();

			new HTMLElementList(
					this[lastIndex]
				)
				.show();

			new HTMLElementList(
					this[this.index]
				)
				.setData(
					"switchstatus",
					switchStatus
				)
				.show();

			return this;
		},
		toSwitch : function(index, _switchStatus){
			if(
				this.length === 0
			){
				return this;
			}

			if(
				index < 0
			){
				index = this.isLoop ? this.max : 0;
			}
			else if(
				index > this.max
			){
				index = this.isLoop ? 0 : this.max;
			}

			if(
				index !== this.index || _switchStatus === SlideTabSwitchStatus.Init
			){
				var lastIndex = this.index;
				
				if(
					typeof _switchStatus === "undefined"
				){
					_switchStatus = lastIndex > index ? SlideTabSwitchStatus.Previous : SlideTabSwitchStatus.Next;
				}

				this.index = index;
				
				this.reshow(lastIndex, _switchStatus);

				unswitchtabEvent.trigger(
					this[lastIndex]
				);

				switchtabEvent.trigger(
					this[index],
					{
						index : index,
						lastIndex : lastIndex,
						switchStatus : _switchStatus
					}
				);
			}
			
			return this;
		}
	});

	return SlideTab.constructor;
}(
	this.SlideTabSwitchStatus,
	// switchtabEvent
	new Event("switchtab"),
	// unswitchtabEvent
	new Event("unswitchtab"),
	Math.ceil
));

this.SlideButton = (function(html, slidebuttonclickEvent){
	function SlideButton(length){
		var slideButton = this;

		this.combine(
				html.create({ length : length }, true)
			)
			.focus(
				0
			)
			.attach({
				click : function(e, targetList){
					if(
						!targetList.isBtw("button", this)
					){
						return;
					}

					var index = targetList.getData("index") - 0;

					slideButton
						.dispatch(
							slidebuttonclickEvent,
							{ index : index }
						)
						.focus(
							index
						);
				}
			});
	};
	SlideButton = new Class(SlideButton, "jQun.SlideButton", HTMLElementList.prototype);

	SlideButton.override({
		focus : function(index){
			this.query(
					'button[data-focus]'
				)
				.removeData(
					"focus"
				);

			this.query(
					'button[data-index="' + index + '"]'
				)
				.setData(
					"focus"
				);

			return this;
		}
	});

	return SlideButton.constructor;
}(
	// html
	new HTML([
		'<div class="slideButton">',
			'@for(',
				'length ->> i',
			'){',
				'<button data-index="{i}" data-bgcolor="white"></button>',
			'}',
		'</div>'
	].join("")),
	// slidebuttonclickEvent
	new Event("slidebuttonclick")
));

this.TiledSlideTab = (function(SlideTab){
	function TiledSlideTab(selector){
		
	};
	TiledSlideTab = new Class(TiledSlideTab, "jQun.TiledSlideTab", SlideTab.prototype);

	TiledSlideTab.override({
		breakLoop : null,
		hide : function(){},
		isLoop : false,
		openLoop : null
	});

	return TiledSlideTab.constructor;
}(
	this.SlideTab
));

this.TiledMobileSlide = (function(TiledSlideTab, SlideTabSwitchStatus, round, setTransform){
	function TiledMobileSlide(selector, _tabSelector){
		var tiledSlideTab, length, tiledMobileSlide = this,
		
			x = 0, lastClientX = 0;

		this.assign({
			tab : new TiledSlideTab(
				this.query(_tabSelector || ">*")
			)
		});

		this.classList.add("tiledSlide");

		tiledSlideTab = this.tab;
		length = tiledSlideTab.length;

		this.attach({
			switchtab : function(e){
				var index = e.index, width = tiledMobileSlide.width,
				
					max = round(width - tiledMobileSlide.parent().width);

				x = round(index * width / tiledMobileSlide.tab.length) * -1;

				if(
					x > 0
				){
					x = 0;
				}
				else if(
					x < max * -1
				){
					x = max * -1;
				}

				setTransform(tiledMobileSlide, x);
			},
			touchstart : function(e){
				tiledMobileSlide.setData("running");

				lastClientX = e.changedTouches[0].clientX;
			},
			touchmove : function(e){
				var clientX = e.changedTouches[0].clientX;

				e.preventDefault();

				x += round(clientX - lastClientX);
				lastClientX = clientX;

				setTransform(tiledMobileSlide, x);
			},
			touchend : function(){
				var tab = tiledMobileSlide.tab, width = tiledMobileSlide.width;

				if(
					x > 0
				){
					tab.toSwitch(0, SlideTabSwitchStatus.Init);
				}
				else if(
					x < round(width - tiledMobileSlide.parent().width) * -1
				){
					tab.toSwitch(tab.length - 1, SlideTabSwitchStatus.Init);
				}
				else {
					tab.toSwitch(
						round(
							(x * -1 / width) / (1 / tab.length)
						),
						SlideTabSwitchStatus.Init
					);
				}

				tiledMobileSlide.removeData("running");
			}
		});
	};
	TiledMobileSlide = new Class(TiledMobileSlide, "jQun.TiledMobileSlide", HTMLElementList.prototype);

	TiledMobileSlide.props({
		tab : null
	});

	return TiledMobileSlide.constructor;
}(
	this.TiledSlideTab,
	this.SlideTabSwitchStatus,
	Math.round,
	// setTransform
	function(tiledMobileSlide, x){
		tiledMobileSlide
			.setCSSPropertyValue(
				"webkitTransform",
				"translateX(" + x + "px)"
			)
			.setCSSPropertyValue(
				"transform",
				"translateX(" + x + "px)"
			);
	}
));

this.ISilde = (function(){
	return new Interface(
		["type"],
		HTMLElementList.prototype
	);
}());

this.Slide = (function(ISilde, SlideTab, SlideButton, SlideDirs, SlideTypes, abs){
	function Slide(selector, _dir, _tabSelector, _isLoop){
		var slideButton, slideTab, slide = this;
		
		this.assign({
				tab : new SlideTab(
					this.query(_tabSelector || ">*"),
					_isLoop
				)
			})
			.setDir(
				_dir || SlideDirs.Horizontal
			);

		this.classList.add("slide");

		slideTab = this.tab;
		slideButton = new SlideButton(slideTab.length);

		slideTab
			.attach({
				switchtab : function(e){
					slideButton.focus(e.index);
				}
			});

		slideButton
			.attach({
				slidebuttonclick : function(e){
					slideTab.toSwitch(e.index);
				}
			})
			.appendTo(
				this[0]
			);

		if(
			this.type === SlideTypes.Mobile
		){
			return;
		}

		var slide = this;

		this.attach({
			mousedown : function(e){
				slide.start(e);
			},
			mouseup : function(e){
				slide.end(e);
			}
		});
	};
	Slide = new Class(Slide, "jQun.Slide", ISilde);

	Slide.props({
		end : function(e){
			if(
				!this.isRunning
			){
				return this;
			}

			this.isRunning = false;

			if(
				!this.userControllable
			){
				return this;
			}

			var offset = e[this.isHorizontal ? "clientX" : "clientY"],
			
				diff = this.offset - offset;

			if(
				abs(diff) > 50
			){
				this.tab[diff > 0 ? "next" : "previous"]();
			}
			
			this.offset = 0;

			return this;
		},
		disableUserControl : function(){
			this.userControllable = false;

			return this;
		},
		enableUserControl : function(){
			this.userControllable = true;

			return this;
		},
		isHorizontal : true,
		isRunning : false,
		offset : 0,
		setDir : function(dir){
			this.isHorizontal = dir === SlideDirs.Horizontal;

			this.setData("dir", dir);
			return this;
		},
		start : function(e){
			if(
				!this.userControllable
			){
				return this;
			}

			this.offset = e[this.isHorizontal ? "clientX" : "clientY"];

			if(
				this.isRunning
			){
				return this;
			}

			this.isRunning = true;
			return this;
		},
		tab : null,
		type : SlideTypes.PC,
		userControllable : true
	});

	return Slide.constructor;
}(
	this.ISilde,
	this.SlideTab,
	this.SlideButton,
	this.SlideDirs,
	this.SlideTypes,
	Math.abs
));

this.MobileSlide = (function(Slide, SlideTypes){
	function MobileSlide(selector, _dir, _tabSelector, _isLoop){
		var slide = this;

		this.attach({
			touchstart : function(e){
				slide.start(e.changedTouches[0]);
			},
			touchmove : function(e){
				e.preventDefault();
			},
			touchend : function(e){
				slide.end(e.changedTouches[0]);
			}
		});
	};
	MobileSlide = new Class(MobileSlide, "jQun.MobileSlide", Slide.prototype);

	MobileSlide.override({
		type : SlideTypes.Mobile
	});

	return MobileSlide.constructor;
}(
	this.Slide,
	this.SlideTypes
));

defineProperties(jQun, this);
}(
	jQun,
	jQun.Class,
	jQun.Interface,
	jQun.Enum,
	jQun.HTMLElementList,
	jQun.Event,
	jQun.HTML,
	jQun.defineProperties
);